
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>五个线程并发的去处理一个任务，不能用锁，怎么保证线程一个一个的处理任务？ - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>五个线程并发的去处理一个任务，不能用锁，怎么保证线程一个一个的处理任务？ - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">在多线程并发场景下，若不希望使用显式锁，有哪些方法可以实现任务的顺序执行？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以使用 Semaphore (信号量)、AtomicInteger (原子整型)、Exchanger (交换器)、BlockingQueue (阻塞队列) 或 Condition (条件变量) 等并发工具来实现任务的顺序处理。</div>
          </div>
          <div class="card-source">来源: 文档开篇部分</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">如何使用 Semaphore 来确保多个线程按顺序处理任务？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">通过初始化一个许可数(permits)为1的 Semaphore。每个线程在执行任务前必须调用 `acquire()` 方法获取唯一许可，执行完毕后调用 `release()` 方法释放许可，从而保证了同一时间只有一个线程能够执行任务。</div>
          </div>
          <div class="card-source">来源: 1. 使用Semaphore（信号量）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">利用 AtomicInteger 实现线程顺序执行的核心机制是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心机制是使用一个 AtomicInteger 作为全局的任务索引计数器。每个线程被分配一个唯一的ID，并在一个循环中不断检查自己的ID是否与 AtomicInteger 的当前值匹配。只有当ID匹配时，线程才执行任务，并原子性地增加计数器的值，以允许下一个线程执行。</div>
          </div>
          <div class="card-source">来源: 2. 使用AtomicInteger（原子整型）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">BlockingQueue 是如何通过生产者/消费者模式来控制任务执行顺序的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">通过使用一个容量为1的 BlockingQueue。第一个线程作为初始生产者，完成任务后向队列中放入一个“信号”。后续的线程扮演消费者的角色，它们必须先从队列中取出（take）上一个线程留下的信号，才能开始执行自己的任务，完成后再放入新的信号以通知下一个线程。</div>
          </div>
          <div class="card-source">来源: 4. 使用BlockingQueue（阻塞队列）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">Condition（条件变量）是如何与Lock配合，实现线程间的等待和通知以保证顺序执行的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">线程首先获取锁（Lock），然后检查执行条件（例如，当前任务索引是否轮到自己）。如果不满足，则调用 `condition.await()` 方法释放锁并进入等待状态。当一个线程完成任务后，它会更新条件，并调用 `condition.signalAll()` 唤醒所有等待的线程，让它们重新竞争锁并检查条件。</div>
          </div>
          <div class="card-source">来源: 5. 使用Condition（条件变量）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">Exchanger 主要用于什么场景？在文档中它是如何被用来协调多个线程的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Exchanger 主要用于两个线程之间进行同步和数据交换。在文档的实现方式中，它被扩展用于多个线程，线程通过 `exchange()` 方法进行同步，像接力一样，确保一个线程处理完任务后，才能与下一个线程完成交换，从而按顺序处理任务。</div>
          </div>
          <div class="card-source">来源: 3. 使用Exchanger（交换器）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在 `Semaphore` 方案中，将许可数设置为1起到了什么关键作用？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">将许可数设置为1，将 Semaphore 变成了一个二元信号量（或称互斥锁），它限制了同时访问任务处理代码块的线程数量为一个。这确保了任务是一个接一个地被串行处理的，即使有多个线程在并发请求。</div>
          </div>
          <div class="card-source">来源: 1. 使用Semaphore（信号量）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">在 `BlockingQueue` 方案中，为什么通常选择容量为1的队列来实现任务的顺序执行？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">选择容量为1的队列是为了强制实现严格的“一进一出”交接。这确保了在任何时刻，队列中最多只有一个待处理的“执行许可”，从而阻止了后续线程在当前线程完成前开始执行，保证了任务严格的先后顺序。</div>
          </div>
          <div class="card-source">来源: 4. 使用BlockingQueue（阻塞队列）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">与使用 `Condition` 的等待/通知机制相比，`AtomicInteger` 方案中的线程是如何等待执行时机的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在 `AtomicInteger` 方案中，线程通过在一个循环中不断地检查 `AtomicInteger` 的当前值（即“自旋”或“忙等待”），来等待轮到自己执行。而 `Condition` 机制则是让不满足条件的线程进入等待状态（`await`），从而释放CPU资源，直到被其他线程唤醒（`signalAll`）。</div>
          </div>
          <div class="card-source">来源: 2. 使用AtomicInteger（原子整型）</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
